package com.study.concurrency;

import java.util.Map;
import java.util.concurrent.*;

public class Hyjal<A, V> implements Computable<A, V> {

    private final Map<A, Future<V>> cache = new ConcurrentHashMap<>();
    private final Computable<A, V> c;

    public Hyjal(Computable<A, V> c) {
        this.c = c;
    }

    @Override

    public V compute(final A args) throws InterruptedException {
        while (true) {
            Future<V> f = cache.get(args);
            if (f == null) {
                FutureTask<V> ft = new FutureTask<>(() -> c.compute(args));

                f = ft;
                cache.putIfAbsent(args, ft);
                ft.run();
            }

            try {
                return f.get();
            } catch (CancellationException e) {
                cache.remove(args, f);
            } catch (ExecutionException e) {
                throw launderThrowable(e);
            }
        }
    }

    public static RuntimeException launderThrowable(Throwable t) {
        if (t instanceof RuntimeException) {
            return (RuntimeException) t;
        } else if (t instanceof Error) {
            return (RuntimeException) t;
        } else {
            throw new IllegalStateException("Not unchecked", t);
        }
    }

}
